import * as vscode from 'vscode';
import * as fs from 'fs';
import * as path from 'path';

/**
 * 日志条目接口
 */
export interface LogEntry {
    timestamp: string;
    type: 'access' | 'error';
    status?: number;
    ip?: string;
    method?: string;
    path?: string;
    size?: number;
    message?: string;
    file?: string;
    line?: number;
}

/**
 * 分析结果接口
 */
export interface AnalysisResult {
    totalEntries: number;
    accessCount: number;
    errorCount: number;
    statusCodes: Record<number, number>;
    topIPs: Array<{ ip: string; count: number }>;
    topPaths: Array<{ path: string; count: number }>;
    errorDistribution: Array<{ file: string; count: number }>;
}

/**
 * Nginx日志分析器类
 */
export class LogAnalyzer {
    private diagnosticCollection: vscode.DiagnosticCollection;

    /**
     * 构造函数
     */
    constructor() {
        this.diagnosticCollection = vscode.languages.createDiagnosticCollection('nginx-logs');
    }

    /**
     * 分析日志
     * @param logEntries 日志条目数组
     * @returns 分析结果
     */
    analyzeLog(logEntries: LogEntry[]): AnalysisResult {
        // 初始化结果
        const result: AnalysisResult = {
            totalEntries: logEntries.length,
            accessCount: 0,
            errorCount: 0,
            statusCodes: {},
            topIPs: [],
            topPaths: [],
            errorDistribution: []
        };

        // 统计IP和路径
        const ipCounts: Record<string, number> = {};
        const pathCounts: Record<string, number> = {};
        const errorFileCounts: Record<string, number> = {};

        // 分析每个日志条目
        for (const entry of logEntries) {
            if (entry.type === 'access') {
                result.accessCount++;

                // 统计状态码
                if (entry.status) {
                    result.statusCodes[entry.status] = (result.statusCodes[entry.status] || 0) + 1;
                }

                // 统计IP
                if (entry.ip) {
                    ipCounts[entry.ip] = (ipCounts[entry.ip] || 0) + 1;
                }

                // 统计路径
                if (entry.path) {
                    pathCounts[entry.path] = (pathCounts[entry.path] || 0) + 1;
                }
            } else if (entry.type === 'error') {
                result.errorCount++;

                // 统计错误文件
                if (entry.file) {
                    errorFileCounts[entry.file] = (errorFileCounts[entry.file] || 0) + 1;
                }

                // 添加诊断信息
                if (entry.file && entry.line) {
                    this.addDiagnostic(entry.file, entry.line - 1, entry.message || '未知错误');
                }
            }
        }

        // 转换计数为排序数组
        result.topIPs = Object.entries(ipCounts)
            .map(([ip, count]) => ({ ip, count }))
            .sort((a, b) => b.count - a.count)
            .slice(0, 10);

        result.topPaths = Object.entries(pathCounts)
            .map(([path, count]) => ({ path, count }))
            .sort((a, b) => b.count - a.count)
            .slice(0, 10);

        result.errorDistribution = Object.entries(errorFileCounts)
            .map(([file, count]) => ({ file, count }))
            .sort((a, b) => b.count - a.count);

        return result;
    }

    /**
     * 生成分析报告
     * @param result 分析结果
     * @param outputPath 输出路径
     * @returns 报告文件路径
     */
    async generateReport(result: AnalysisResult, outputPath?: string): Promise<string> {
        // 如果没有提供输出路径，使用临时目录
        if (!outputPath) {
            const workspaceFolders = vscode.workspace.workspaceFolders;
            if (!workspaceFolders) {
                throw new Error('No workspace folder is open');
            }
            
            outputPath = path.join(workspaceFolders[0].uri.fsPath, 'nginx-log-analysis-report.md');
        }
        
        // 创建报告内容
        const content = this.createReportContent(result);
        
        // 写入文件
        fs.writeFileSync(outputPath, content, 'utf8');
        
        // 打开报告文件
        const document = await vscode.workspace.openTextDocument(outputPath);
        await vscode.window.showTextDocument(document);
        
        return outputPath;
    }

    /**
     * 创建报告内容
     * @param result 分析结果
     * @returns 报告内容
     */
    private createReportContent(result: AnalysisResult): string {
        return `# Nginx 日志分析报告

## 概览

- **总日志条目**: ${result.totalEntries}
- **访问日志数**: ${result.accessCount}
- **错误日志数**: ${result.errorCount}

## HTTP 状态码分布

${Object.entries(result.statusCodes)
    .sort(([a], [b]) => parseInt(a) - parseInt(b))
    .map(([code, count]) => `- ${code}: ${count} 次`)
    .join('\n')}

## 访问量最高的IP

${result.topIPs
    .map(({ ip, count }) => `- ${ip}: ${count} 次`)
    .join('\n')}

## 访问量最高的路径

${result.topPaths
    .map(({ path, count }) => `- ${path}: ${count} 次`)
    .join('\n')}

## 错误分布

${result.errorDistribution
    .map(({ file, count }) => `- ${file}: ${count} 错误`)
    .join('\n')}

## 建议

${this.generateSuggestions(result)}

---

*报告生成时间: ${new Date().toLocaleString()}*
`;
    }

    /**
     * 根据分析结果生成建议
     * @param result 分析结果
     * @returns 建议文本
     */
    private generateSuggestions(result: AnalysisResult): string {
        const suggestions: string[] = [];
        
        // 检查404错误
        const notFoundCount = result.statusCodes[404] || 0;
        if (notFoundCount > 0) {
            suggestions.push(`- 发现 ${notFoundCount} 个404错误，请检查资源路径是否正确，或者添加相应的重定向规则。`);
        }
        
        // 检查服务器错误
        const serverErrorCount = Object.entries(result.statusCodes)
            .filter(([code]) => parseInt(code) >= 500)
            .reduce((sum, [_, count]) => sum + count, 0);
            
        if (serverErrorCount > 0) {
            suggestions.push(`- 发现 ${serverErrorCount} 个服务器错误，请查看详细错误日志并修复相关问题。`);
        }
        
        // 检查高访问量IP
        if (result.topIPs.length > 0 && result.topIPs[0].count > 0.5 * result.accessCount) {
            suggestions.push(`- IP ${result.topIPs[0].ip} 的访问量占总访问量的 ${Math.round(result.topIPs[0].count / result.accessCount * 100)}%，请注意可能的爬虫或攻击行为。`);
        }
        
        // 如果没有建议
        if (suggestions.length === 0) {
            suggestions.push('- 日志分析未发现明显问题。');
        }
        
        return suggestions.join('\n');
    }

    /**
     * 解析访问日志
     * @param logText 日志文本
     * @returns 日志条目数组
     */
    parseAccessLog(logText: string): LogEntry[] {
        const entries: LogEntry[] = [];
        const lines = logText.split('\n');
        
        // 常见的访问日志格式正则表达式
        const regex = /(\S+) - (\S+) \[([^\]]+)\] "(\S+) ([^"]+) HTTP\/[\d.]+" (\d+) (\d+)/;
        
        for (const line of lines) {
            if (!line.trim()) continue;
            
            const match = line.match(regex);
            if (match) {
                entries.push({
                    timestamp: match[3],
                    type: 'access',
                    ip: match[1],
                    method: match[4],
                    path: match[5],
                    status: parseInt(match[6]),
                    size: parseInt(match[7])
                });
            } else {
                // 尝试从非标准格式中提取信息
                const ipMatch = line.match(/(\d+\.\d+\.\d+\.\d+)/);
                const statusMatch = line.match(/\s(\d{3})\s/);
                
                if (ipMatch || statusMatch) {
                    entries.push({
                        timestamp: new Date().toISOString(),
                        type: 'access',
                        ip: ipMatch ? ipMatch[1] : undefined,
                        status: statusMatch ? parseInt(statusMatch[1]) : undefined,
                        message: line
                    });
                }
            }
        }
        
        return entries;
    }

    /**
     * 解析错误日志
     * @param logText 日志文本
     * @returns 日志条目数组
     */
    parseErrorLog(logText: string): LogEntry[] {
        const entries: LogEntry[] = [];
        const lines = logText.split('\n');
        
        // 错误日志正则表达式
        const dateRegex = /(\d{4}\/\d{2}\/\d{2} \d{2}:\d{2}:\d{2})/;
        const fileLineRegex = /in (\S+):(\d+)/;
        
        for (const line of lines) {
            if (!line.trim()) continue;
            
            const dateMatch = line.match(dateRegex);
            const fileLineMatch = line.match(fileLineRegex);
            
            const entry: LogEntry = {
                timestamp: dateMatch ? dateMatch[1] : new Date().toISOString(),
                type: 'error',
                message: line
            };
            
            if (fileLineMatch) {
                entry.file = fileLineMatch[1];
                entry.line = parseInt(fileLineMatch[2]);
            }
            
            entries.push(entry);
        }
        
        return entries;
    }

    /**
     * 添加诊断信息
     * @param filePath 文件路径
     * @param line 行号
     * @param message 错误消息
     */
    private addDiagnostic(filePath: string, line: number, message: string): void {
        try {
            // 检查文件是否存在
            if (!fs.existsSync(filePath)) {
                return;
            }
            
            // 创建诊断对象
            const diagnostic = new vscode.Diagnostic(
                new vscode.Range(line, 0, line, 100),
                `Nginx错误: ${message}`,
                vscode.DiagnosticSeverity.Error
            );
            
            // 获取已有诊断
            const uri = vscode.Uri.file(filePath);
            const existingDiagnostics = this.diagnosticCollection.get(uri) || [];
            
            // 添加新诊断
            this.diagnosticCollection.set(uri, [...existingDiagnostics, diagnostic]);
        } catch (error) {
            console.error('Error adding diagnostic:', error);
        }
    }

    /**
     * 清除诊断信息
     */
    clearDiagnostics(): void {
        this.diagnosticCollection.clear();
    }

    /**
     * 处置资源
     */
    dispose(): void {
        this.diagnosticCollection.dispose();
    }
} 